home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / ed.xmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  15.3 KB  |  635 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/ed.xmap.c,v 3.5 1991/11/26 04:28:26 christos Exp $ */
  2. /*
  3.  * ed.xmap.c: This module contains the procedures for maintaining
  4.  *          the extended-key map.
  5.  *
  6.  *           An extended-key (Xkey) is a sequence of keystrokes
  7.  *          introduced with an sequence introducer and consisting
  8.  *          of an arbitrary number of characters.  This module maintains
  9.  *          a map (the Xmap) to convert these extended-key sequences
  10.  *           into input strings (XK_STR), editor functions (XK_CMD), or
  11.  *          unix commands (XK_EXE). It contains the
  12.  *          following externally visible functions.
  13.  *
  14.  *        int GetXkey(ch,val);
  15.  *        Char *ch;
  16.  *        XmapVal *val;
  17.  *
  18.  *          Looks up *ch in map and then reads characters until a
  19.  *          complete match is found or a mismatch occurs. Returns the
  20.  *          type of the match found (XK_STR, XK_CMD, or XK_EXE).
  21.  *          Returns NULL in val.str and XK_STR for no match.  
  22.  *          The last character read is returned in *ch.
  23.  *
  24.  *        void AddXkey(Xkey, val, ntype);
  25.  *        Char *Xkey;
  26.  *        XmapVal *val;
  27.  *        int ntype;
  28.  *
  29.  *          Adds Xkey to the Xmap and associates the value in val with it.
  30.  *          If Xkey is already is in Xmap, the new code is applied to the
  31.  *          existing Xkey. Ntype specifies if code is a command, an
  32.  *          out string or a unix command.
  33.  *
  34.  *            int DeleteXkey(Xkey);
  35.  *            Char *Xkey;
  36.  *
  37.  *          Delete the Xkey and all longer Xkeys staring with Xkey, if
  38.  *          they exists.
  39.  *
  40.  *          Warning:
  41.  *        If Xkey is a substring of some other Xkeys, then the longer
  42.  *        Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
  43.  *        are in Xmap, adding the key "abc" will cause the first two
  44.  *        definitions to be lost.
  45.  *
  46.  *        void ResetXmap();
  47.  *
  48.  *          Removes all entries from Xmap and resets the defaults.
  49.  *
  50.  *        void PrintXkey(Xkey);
  51.  *        Char *Xkey;
  52.  *
  53.  *          Prints all extended keys prefixed by Xkey and their associated
  54.  *          commands.
  55.  *
  56.  *          Restrictions:
  57.  *          -------------
  58.  *            1) It is not possible to have one Xkey that is a
  59.  *           substring of another.
  60.  */
  61. /*-
  62.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  63.  * All rights reserved.
  64.  *
  65.  * Redistribution and use in source and binary forms, with or without
  66.  * modification, are permitted provided that the following conditions
  67.  * are met:
  68.  * 1. Redistributions of source code must retain the above copyright
  69.  *    notice, this list of conditions and the following disclaimer.
  70.  * 2. Redistributions in binary form must reproduce the above copyright
  71.  *    notice, this list of conditions and the following disclaimer in the
  72.  *    documentation and/or other materials provided with the distribution.
  73.  * 3. All advertising materials mentioning features or use of this software
  74.  *    must display the following acknowledgement:
  75.  *    This product includes software developed by the University of
  76.  *    California, Berkeley and its contributors.
  77.  * 4. Neither the name of the University nor the names of its contributors
  78.  *    may be used to endorse or promote products derived from this software
  79.  *    without specific prior written permission.
  80.  *
  81.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  82.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  83.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  84.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  85.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  86.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  87.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  88.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  89.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  90.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  91.  * SUCH DAMAGE.
  92.  */
  93. #include "sh.h"
  94.  
  95. RCSID("$Id: ed.xmap.c,v 3.5 1991/11/26 04:28:26 christos Exp $")
  96.  
  97. #include "ed.h"
  98. #include "ed.defns.h"
  99.  
  100. #ifndef NULL
  101. #define NULL 0
  102. #endif
  103.  
  104. /* Internal Data types and declarations */
  105.  
  106. /* The Nodes of the Xmap.  The Xmap is a linked list of these node
  107.  * elements
  108.  */
  109. typedef struct Xmapnode {
  110.     Char    ch;            /* single character of Xkey */
  111.     int     type;
  112.     XmapVal val;         /* command code or pointer to string, if this
  113.                  * is a leaf */
  114.     struct Xmapnode *next;    /* ptr to next char of this Xkey */
  115.     struct Xmapnode *sibling;    /* ptr to another Xkey with same prefix */
  116. } XmapNode;
  117.  
  118. static XmapNode *Xmap = NULL;    /* the current Xmap */
  119. #define MAXXKEY 100        /* max length of a Xkey for print putposes */
  120. static Char printbuf[MAXXKEY];    /* buffer for printing */
  121.  
  122.  
  123. /* Some declarations of procedures */
  124. static    int       TraverseMap    __P((XmapNode *, Char *, XmapVal *));
  125. static    int       TryNode    __P((XmapNode *, Char *, XmapVal *, int));
  126. static    XmapNode *GetFreeNode    __P((int));
  127. static    void      PutFreeNode    __P((XmapNode *));
  128. static    int      TryDeleteNode    __P((XmapNode **, Char *));
  129. static    int      Lookup    __P((Char *, XmapNode *, int));
  130. static    int      Enumerate    __P((XmapNode *, int));
  131. static    int      printOne    __P((Char *, XmapVal *, int));
  132. static    int      unparsech    __P((int, int));
  133.  
  134.  
  135. XmapVal *
  136. XmapCmd(cmd)
  137.     int cmd;
  138. {
  139.     static XmapVal xm;
  140.     xm.cmd = cmd;
  141.     return &xm;
  142. }
  143.  
  144. XmapVal *
  145. XmapStr(str)
  146.     Char  *str;
  147. {
  148.     static XmapVal xm;
  149.     xm.str = str;
  150.     return &xm;
  151. }
  152.  
  153. /* ResetXmap():
  154.  *    Takes all nodes on Xmap and puts them on free list.  Then
  155.  *    initializes Xmap with arrow keys
  156.  */
  157. void
  158. ResetXmap(vi)
  159.     int     vi;
  160. {
  161.     static Char strA[] = {033, '[', 'A', '\0'};
  162.     static Char strB[] = {033, '[', 'B', '\0'};
  163.     static Char strC[] = {033, '[', 'C', '\0'};
  164.     static Char strD[] = {033, '[', 'D', '\0'};
  165.     static Char stOA[] = {033, 'O', 'A', '\0'};
  166.     static Char stOB[] = {033, 'O', 'B', '\0'};
  167.     static Char stOC[] = {033, 'O', 'C', '\0'};
  168.     static Char stOD[] = {033, 'O', 'D', '\0'};
  169.  
  170.     PutFreeNode(Xmap);
  171.     Xmap = NULL;
  172.     AddXkey(strA, XmapCmd(F_UP_HIST),   XK_CMD);
  173.     AddXkey(strB, XmapCmd(F_DOWN_HIST), XK_CMD);
  174.     AddXkey(strC, XmapCmd(F_CHARFWD),   XK_CMD);
  175.     AddXkey(strD, XmapCmd(F_CHARBACK),  XK_CMD);
  176.     AddXkey(stOA, XmapCmd(F_UP_HIST),   XK_CMD);
  177.     AddXkey(stOB, XmapCmd(F_DOWN_HIST), XK_CMD);
  178.     AddXkey(stOC, XmapCmd(F_CHARFWD),   XK_CMD);
  179.     AddXkey(stOD, XmapCmd(F_CHARBACK),  XK_CMD);
  180.     if (vi) {
  181.     AddXkey(&strA[1], XmapCmd(F_UP_HIST),   XK_CMD);
  182.     AddXkey(&strB[1], XmapCmd(F_DOWN_HIST), XK_CMD);
  183.     AddXkey(&strC[1], XmapCmd(F_CHARFWD),   XK_CMD);
  184.     AddXkey(&strD[1], XmapCmd(F_CHARBACK),  XK_CMD);
  185.     AddXkey(&stOA[1], XmapCmd(F_UP_HIST),   XK_CMD);
  186.     AddXkey(&stOB[1], XmapCmd(F_DOWN_HIST), XK_CMD);
  187.     AddXkey(&stOC[1], XmapCmd(F_CHARFWD),   XK_CMD);
  188.     AddXkey(&stOD[1], XmapCmd(F_CHARBACK),  XK_CMD);
  189.     }
  190.     return;
  191. }
  192.  
  193.  
  194. /* GetXkey():
  195.  *    Calls the recursive function with entry point Xmap
  196.  */
  197. int
  198. GetXkey(ch, val)
  199.     Char     *ch;
  200.     XmapVal  *val;
  201. {
  202.     return (TraverseMap(Xmap, ch, val));
  203. }
  204.  
  205. /* TraverseMap():
  206.  *    recursively traverses node in tree until match or mismatch is
  207.  *     found.  May read in more characters.
  208.  */
  209. static int
  210. TraverseMap(ptr, ch, val)
  211.     XmapNode *ptr;
  212.     Char     *ch;
  213.     XmapVal  *val;
  214. {
  215.     Char    tch;
  216.  
  217.     if (ptr->ch == *ch) {
  218.     /* match found */
  219.     if (ptr->next) {
  220.         /* Xkey not complete so get next char */
  221.         if (GetNextChar(&tch) != 1) {    /* if EOF or error */
  222.         val->cmd = F_SEND_EOF;
  223.         return XK_CMD;/* PWP: Pretend we just read an end-of-file */
  224.         }
  225.         *ch = tch;
  226.         return (TraverseMap(ptr->next, ch, val));
  227.     }
  228.     else {
  229.         *val = ptr->val;
  230.         if (ptr->type != XK_CMD)
  231.         *ch = '\0';
  232.         return ptr->type;
  233.     }
  234.     }
  235.     else {
  236.     /* no match found here */
  237.     if (ptr->sibling) {
  238.         /* try next sibling */
  239.         return (TraverseMap(ptr->sibling, ch, val));
  240.     }
  241.     else {
  242.         /* no next sibling -- mismatch */
  243.         val->str = NULL;
  244.         return XK_STR;
  245.     }
  246.     }
  247. }
  248.  
  249. void
  250. AddXkey(Xkey, val, ntype)
  251.     Char    *Xkey;
  252.     XmapVal *val;
  253.     int      ntype;
  254. {
  255.     if (Xkey[0] == '\0') {
  256.     xprintf("AddXkey: Null extended-key not allowed.\n");
  257.     return;
  258.     }
  259.  
  260.     if (ntype == XK_CMD && val->cmd == F_XKEY) {
  261.     xprintf("AddXkey: sequence-lead-in command not allowed\n");
  262.     return;
  263.     }
  264.  
  265.     if (Xmap == NULL)
  266.     /* tree is initially empty.  Set up new node to match Xkey[0] */
  267.     Xmap = GetFreeNode(Xkey[0]);    /* it is properly initialized */
  268.  
  269.     /* Now recurse through Xmap */
  270.     (void) TryNode(Xmap, Xkey, val, ntype);    
  271.     return;
  272. }
  273.  
  274. static int
  275. TryNode(ptr, string, val, ntype)
  276.     XmapNode *ptr;
  277.     Char     *string;
  278.     XmapVal  *val;
  279.     int       ntype;
  280. {
  281.     /*
  282.      * Find a node that matches *string or allocate a new one
  283.      */
  284.     if (ptr->ch != *string) {
  285.     XmapNode *xm;
  286.  
  287.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  288.         if (xm->sibling->ch == *string)
  289.         break;
  290.     if (xm->sibling == NULL)
  291.         xm->sibling = GetFreeNode(*string);    /* setup new node */
  292.     ptr = xm->sibling;
  293.     }
  294.  
  295.     if (*++string == '\0') {
  296.     /* we're there */
  297.     if (ptr->next != NULL) {
  298.         PutFreeNode(ptr->next);    /* lose longer Xkeys with this prefix */
  299.         ptr->next = NULL;
  300.     }
  301.     switch (ptr->type = ntype) {
  302.     case XK_CMD:
  303.         ptr->val = *val;
  304.         break;
  305.     case XK_STR:
  306.     case XK_EXE:
  307.         if (ptr->val.str)
  308.         xfree((ptr_t) ptr->val.str);
  309.         ptr->val.str = Strsave(val->str);
  310.         break;
  311.     default:
  312.         abort();
  313.         break;
  314.     }
  315.     }
  316.     else {
  317.     /* still more chars to go */
  318.     if (ptr->next == NULL)
  319.         ptr->next = GetFreeNode(*string);    /* setup new node */
  320.     (void) TryNode(ptr->next, string, val, ntype);
  321.     }
  322.     return (0);
  323. }
  324.  
  325. void
  326. ClearXkey(map, in)
  327.     KEYCMD *map;
  328.     Char   *in;
  329. {
  330.     if ((map[(unsigned char) *in] == F_XKEY) &&
  331.     ((map == CcKeyMap && CcAltMap[(unsigned char) *in] != F_XKEY) ||
  332.      (map == CcAltMap && CcKeyMap[(unsigned char) *in] != F_XKEY)))
  333.     (void) DeleteXkey(in);
  334. }
  335.  
  336. int
  337. DeleteXkey(Xkey)
  338.     Char   *Xkey;
  339. {
  340.     if (Xkey[0] == '\0') {
  341.     xprintf("DeleteXkey: Null extended-key not allowed.\n");
  342.     return (-1);
  343.     }
  344.  
  345.     if (Xmap == NULL)
  346.     return (0);
  347.  
  348.     (void) TryDeleteNode(&Xmap, Xkey);
  349.     return (0);
  350. }
  351.  
  352. static int
  353. TryDeleteNode(inptr, string)
  354.     XmapNode **inptr;
  355.     Char   *string;
  356. {
  357.     XmapNode *ptr;
  358.     XmapNode *prev_ptr = NULL;
  359.  
  360.     ptr = *inptr;
  361.     /*
  362.      * Find a node that matches *string or allocate a new one
  363.      */
  364.     if (ptr->ch != *string) {
  365.     XmapNode *xm;
  366.  
  367.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  368.         if (xm->sibling->ch == *string)
  369.         break;
  370.     if (xm->sibling == NULL)
  371.         return (0);
  372.     prev_ptr = xm;
  373.     ptr = xm->sibling;
  374.     }
  375.  
  376.     if (*++string == '\0') {
  377.     /* we're there */
  378.     if (prev_ptr == NULL)
  379.         *inptr = ptr->sibling;
  380.     else
  381.         prev_ptr->sibling = ptr->sibling;
  382.     ptr->sibling = NULL;
  383.     PutFreeNode(ptr);
  384.     return (1);
  385.     }
  386.     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, string) == 1) {
  387.     if (ptr->next != NULL)
  388.         return (0);
  389.     if (prev_ptr == NULL)
  390.         *inptr = ptr->sibling;
  391.     else
  392.         prev_ptr->sibling = ptr->sibling;
  393.     ptr->sibling = NULL;
  394.     PutFreeNode(ptr);
  395.     return (1);
  396.     }
  397.     else {
  398.     return (0);
  399.     }
  400. }
  401.  
  402. /* PutFreeNode():
  403.  *    Puts a tree of nodes onto free list using free(3).
  404.  */
  405. static void
  406. PutFreeNode(ptr)
  407.     XmapNode *ptr;
  408. {
  409.     if (ptr == NULL)
  410.     return;
  411.  
  412.     if (ptr->next != NULL) {
  413.     PutFreeNode(ptr->next);
  414.     ptr->next = NULL;
  415.     }
  416.  
  417.     PutFreeNode(ptr->sibling);
  418.  
  419.     switch (ptr->type) {
  420.     case XK_CMD:
  421.     case XK_NOD:
  422.     break;
  423.     case XK_EXE:
  424.     case XK_STR:
  425.     if (ptr->val.str != NULL)
  426.         xfree((ptr_t) ptr->val.str);
  427.     break;
  428.     default:
  429.     abort();
  430.     break;
  431.     }
  432.     xfree((ptr_t) ptr);
  433. }
  434.  
  435.  
  436. /* GetFreeNode():
  437.  *    Returns pointer to an XmapNode for ch.
  438.  */
  439. static XmapNode *
  440. GetFreeNode(ch)
  441.     int    ch;
  442. {
  443.     XmapNode *ptr;
  444.  
  445.     ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode));
  446.     ptr->ch = ch;
  447.     ptr->type = XK_NOD;
  448.     ptr->val.str = NULL;
  449.     ptr->next = NULL;
  450.     ptr->sibling = NULL;
  451.     return (ptr);
  452. }
  453.  
  454.  
  455. /* PrintXKey():
  456.  *    Print the binding associated with Xkey key.
  457.  *    Print entire Xmap if null
  458.  */
  459. void
  460. PrintXkey(key)
  461.     Char   *key;
  462. {
  463.     /* do nothing if Xmap is empty and null key specified */
  464.     if (Xmap == NULL && *key == 0)
  465.     return;
  466.  
  467.     printbuf[0] =  '"';
  468.     if (Lookup(key, Xmap, 1) <= -1)
  469.     /* key is not bound */
  470.     xprintf("Unbound extended key \"%s\"\n", short2str(key));
  471.     return;
  472. }
  473.  
  474. /* Lookup():
  475.  *    look for the string starting at node ptr.
  476.  *    Print if last node
  477.  */
  478. static int
  479. Lookup(string, ptr, cnt)
  480.     Char   *string;
  481.     XmapNode *ptr;
  482.     int     cnt;
  483. {
  484.     int     ncnt;
  485.  
  486.     if (ptr == NULL)
  487.     return (-1);        /* cannot have null ptr */
  488.  
  489.     if (*string == 0) {
  490.     /* no more chars in string.  Enumerate from here. */
  491.     (void) Enumerate(ptr, cnt);
  492.     return (0);
  493.     }
  494.     else {
  495.     /* If match put this char into printbuf.  Recurse */
  496.     if (ptr->ch == *string) {
  497.         /* match found */
  498.         ncnt = unparsech(cnt, ptr->ch);
  499.         if (ptr->next != NULL)
  500.         /* not yet at leaf */
  501.         return (Lookup(string + 1, ptr->next, ncnt + 1));
  502.         else {
  503.         /* next node is null so key should be complete */
  504.         if (string[1] == 0) {
  505.             printbuf[ncnt + 1] = '"';
  506.             printbuf[ncnt + 2] = '\0';
  507.             (void) printOne(printbuf, &ptr->val, ptr->type);
  508.             return (0);
  509.         }
  510.         else
  511.             return (-1);/* mismatch -- string still has chars */
  512.         }
  513.     }
  514.     else {
  515.         /* no match found try sibling */
  516.         if (ptr->sibling)
  517.         return (Lookup(string, ptr->sibling, cnt));
  518.         else
  519.         return (-1);
  520.     }
  521.     }
  522. }
  523.  
  524. static int
  525. Enumerate(ptr, cnt)
  526.     XmapNode *ptr;
  527.     int     cnt;
  528. {
  529.     int     ncnt;
  530.  
  531.     if (cnt >= MAXXKEY - 5) {    /* buffer too small */
  532.     printbuf[++cnt] = '"';
  533.     printbuf[++cnt] = '\0';
  534.     xprintf("Some extended keys too long for internal print buffer");
  535.     xprintf(" \"%s...\"\n", short2str(printbuf));
  536.     return (0);
  537.     }
  538.  
  539.     if (ptr == NULL) {
  540. #ifdef DEBUG_EDIT
  541.     xprintf("Enumerate: BUG!! Null ptr passed\n!");
  542. #endif
  543.     return (-1);
  544.     }
  545.  
  546.     ncnt = unparsech(cnt, ptr->ch);    /* put this char at end of string */
  547.     if (ptr->next == NULL) {
  548.     /* print this Xkey and function */
  549.     printbuf[ncnt + 1] = '"';
  550.     printbuf[ncnt + 2] = '\0';
  551.     (void) printOne(printbuf, &ptr->val, ptr->type);
  552.     }
  553.     else
  554.     (void) Enumerate(ptr->next, ncnt + 1);
  555.  
  556.     /* go to sibling if there is one */
  557.     if (ptr->sibling)
  558.     (void) Enumerate(ptr->sibling, cnt);
  559.     return (0);
  560. }
  561.  
  562.  
  563. /* PrintOne():
  564.  *    Print the specified key and its associated
  565.  *    function specified by val
  566.  */
  567. static int
  568. printOne(key, val, ntype)
  569.     Char    *key;
  570.     XmapVal *val;
  571.     int      ntype;
  572. {
  573.     struct KeyFuncs *fp;
  574.     unsigned char unparsbuf[200];
  575.     static char *fmt = "%-15s->  %s\n";
  576.  
  577.     if (val != NULL)
  578.     switch (ntype) {
  579.     case XK_STR:
  580.     case XK_EXE:
  581.         xprintf(fmt, short2str(key), 
  582.             unparsestring(val->str, unparsbuf, 
  583.                   ntype == XK_STR ? STRQQ : STRBB));
  584.         break;
  585.     case XK_CMD:
  586.         for (fp = FuncNames; fp->name; fp++)
  587.         if (val->cmd == fp->func)
  588.             xprintf(fmt, short2str(key), fp->name);
  589.         break;
  590.     default:
  591.         abort();
  592.         break;
  593.     }
  594.     else
  595.     xprintf(fmt, short2str(key), "no input");
  596.     return (0);
  597. }
  598.  
  599. static int
  600. unparsech(cnt, ch)
  601.     int     cnt, ch;
  602. {
  603.     if (ch == 0) {
  604.     printbuf[cnt++] = '^';
  605.     printbuf[cnt] = '@';
  606.     return cnt;
  607.     }
  608.  
  609.     if (Iscntrl(ch)) {
  610.     printbuf[cnt++] = '^';
  611.     if (ch == '\177')
  612.         printbuf[cnt] = '?';
  613.     else
  614.         printbuf[cnt] = ch | 0100;
  615.     }
  616.     else if (ch == '^') {
  617.     printbuf[cnt++] = '\\';
  618.     printbuf[cnt] = '^';
  619.     }
  620.     else if (ch == '\\') {
  621.     printbuf[cnt++] = '\\';
  622.     printbuf[cnt] = '\\';
  623.     }
  624.     else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
  625.     printbuf[cnt] = ch;
  626.     }
  627.     else {
  628.     printbuf[cnt++] = '\\';
  629.     printbuf[cnt++] = ((ch >> 6) & 7) + '0';
  630.     printbuf[cnt++] = ((ch >> 3) & 7) + '0';
  631.     printbuf[cnt] = (ch & 7) + '0';
  632.     }
  633.     return cnt;
  634. }
  635.